package com.lzy.cloud.payment.facade;

import com.lzy.cloud.payment.constants.BusinessStatus;
import com.lzy.cloud.payment.constants.CommonConstants;
import com.lzy.cloud.payment.dtos.pay.BasePayDTO;
import com.lzy.cloud.payment.dtos.pay.PayOrderParamsDTO;
import com.lzy.cloud.payment.dtos.payment.PayBillDto;
import com.lzy.cloud.payment.dtos.payment.PayInfoDetailDto;
import com.lzy.cloud.payment.dtos.payment.PayInfoDto;
import com.lzy.cloud.payment.remote.AccountApi;
import com.lzy.cloud.payment.remote.BaseApi;
import com.lzy.cloud.payment.remote.OrderApi;
import com.lzy.cloud.payment.remote.dtos.AccountWalletDto;
import com.lzy.cloud.payment.remote.dtos.AccountWalletInfoDto;
import com.lzy.cloud.payment.remote.dtos.BaseOrderDto;
import com.lzy.cloud.payment.remote.dtos.OrderExpenseItemDto;
import com.lzy.cloud.payment.remote.request.AccountWalletInfoRequest;
import com.lzy.cloud.payment.remote.request.BaseCouponRequest;
import com.lzy.cloud.payment.remote.request.OrderCouponLogRequest;
import com.lzy.cloud.payment.remote.request.OrderExpenseItemRequest;
import com.lzy.cloud.payment.remote.response.OrderCouponLogResponse;
import com.lzy.cloud.payment.service.PayBillService;
import com.lzy.cloud.payment.service.PayInfoDetailService;
import com.lzy.cloud.payment.service.PayInfoService;
import com.lzy.cloud.payment.utils.CommonsUtil;
import com.lzy.framework.core.ensure.Ensure;
import com.lzy.framework.core.output.Result;
import com.lzy.framework.core.utils.DozerUtils;
import com.lzy.framework.tools.commons.BigDecimalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Component
public class PayTradeFacade {

    @Autowired
    PayTradeFacade payTradeFacade;

    @Autowired
    PayInfoService payInfoService;

    @Autowired
    PayInfoDetailService payInfoDetailService;

    @Autowired
    PayBillService payBillService;

    @Autowired
    OrderApi orderApi;

    @Autowired
    AccountApi accountApi;

    @Autowired
    BaseApi baseApi;

    public Boolean notifyProcess(BasePayDTO bpd){
        PayInfoDto payInfoDO = payInfoService.queryPayInfoByOrderId(bpd.getOut_trade_no());
        Ensure.that(payInfoDO == null).isFalse("09000025");  //支付宝，微信异步返回商户订单号不在数据库中
        //当未支付
        if (payInfoDO.getStatus().equals(CommonConstants.OrderPayStatus.NOPAY.getIndex())) {
            bpd.setUserId(payInfoDO.getMemberId());
            bpd.setType(payInfoDO.getType());
            if (updateResult(bpd)) {
                //支付成功
                //添加交易记录
                payInfo(payInfoDO,bpd);
                //订单支付
                if(bpd.getType().equals(BusinessStatus.PayInfoType.pay)) {
                    //扣除冻结金额,并添加资金记录
                    deductBlockBalance(payInfoDO, bpd);
                    //将订单中的卡券解锁定，并将状态更改为已使用，并添加卡券流向记录
                    //根据会员id和订单id找到锁定的卡券id列表
                    deductBlockCoupon(bpd);
                    return true;
                }
                //龙币充值
                if(bpd.getType().equals(BusinessStatus.PayInfoType.lbrecharge)){
                    return LbRecharge(bpd,payInfoDO);
                }
            }
        }
        return false;
    }

    /**
     * 更新订单状态
     * @param bpd
     * @return
     */
    public Boolean updateResult(BasePayDTO bpd){
        switch (bpd.getType()) {
            case BusinessStatus.PayInfoType.pay:
                return pay(bpd);
        }
        return false;
    }

    /**
     * 在线支付
     *
     * @param bpd
     * @return
     */
    public boolean pay(BasePayDTO bpd) {
        PayOrderParamsDTO popDTO = new PayOrderParamsDTO();
        popDTO.setOrderId(bpd.getOut_trade_no());             //订单id
        popDTO.setPayName(CommonConstants.PayWay.getName(bpd.getWay()));    //支付名称
        popDTO.setStutas(CommonConstants.OrderPayStatus.YESPAY.getIndex()); //支付状态
        popDTO.setPayId(bpd.getWay());  //支付方式
        boolean updateOrderFlag = DozerUtils.map(orderApi.updatePayOrderStatus(popDTO).getResult(), Boolean.class);   //更新订单表支付状态
        return updateOrderFlag;
    }

    /**
     * 支付交易流水数据
     *
     * @param payInfoDO
     * @param bpd
     */
    public void payInfo(PayInfoDto payInfoDO, BasePayDTO bpd) {
        Map<String, Object> saveData = PayInfoDto.payInfo(bpd);
        Ensure.that(CommonsUtil.isEmptyMap(saveData)).isFalse("09000026"); //支付表，支付明细表，账单表封装实体异常   --
        PayInfoDto piDO = (PayInfoDto) saveData.get("payInfoDto");
        PayInfoDetailDto payInfoDetailDO = (PayInfoDetailDto) saveData.get("payInfoDetailDto");

        piDO.setId(payInfoDO.getId());
        boolean payId = payInfoService.updatePayInfo(piDO);        //支付表
        Ensure.that(payId).isTrue("09000027");

        payInfoDetailDO.setOpenid(payInfoDO.getId() + "");
        boolean payDflag = payInfoDetailService.createPayInfoDetail(payInfoDetailDO);  //支付明细表
        Ensure.that(payDflag).isTrue("09000028");
    }

    /**
     *订单中的冻结金额扣除
     *
     * @param payInfoDO
     * @param bpd
     */
    public Boolean deductBlockBalance(PayInfoDto payInfoDO, BasePayDTO bpd){
        //将订单中的冻结金额扣除
        Boolean ok = false;
        OrderExpenseItemRequest orderExpenseItemRequest = new OrderExpenseItemRequest();
        orderExpenseItemRequest.setOrderId(bpd.getOut_trade_no());
        orderExpenseItemRequest.setType(1);
        List<OrderExpenseItemDto> orderExpenseItemDtoList = DozerUtils.maps((List)orderApi.queryList(orderExpenseItemRequest).getResult(),OrderExpenseItemDto.class);
        OrderExpenseItemDto oeiDto = orderExpenseItemDtoList.get(0);
        if(oeiDto != null && !BigDecimalUtil.isZeroOrNull(oeiDto.getAmount())){
            //获取该会员钱包中冻结金额数据
            BaseOrderDto baseOrderDto = DozerUtils.map(orderApi.findOrderByOrderId(bpd.getOut_trade_no()),BaseOrderDto.class);
            AccountWalletDto accountWalletDto = DozerUtils.map(accountApi.findByMemberIdAndPlatformId(bpd.getUserId(),baseOrderDto.getShopId()).getResult(),AccountWalletDto.class);
            if(accountWalletDto != null && accountWalletDto.getId() != null){
                AccountWalletInfoDto walletInfoDto = DozerUtils.map(accountApi.findByWalletId(accountWalletDto.getId()).getResult(),AccountWalletInfoDto.class);
                if(walletInfoDto != null && !BigDecimalUtil.isZeroOrNull(walletInfoDto.getBalance())
                        &&walletInfoDto.getBalance().compareTo(oeiDto.getAmount()) >= 0){
                    BigDecimal blockedMoney = walletInfoDto.getBalance().subtract(oeiDto.getAmount());
                    //更新会员钱包中冻结金额数据
                    AccountWalletInfoRequest awiDto = new AccountWalletInfoRequest();
                    awiDto.setBalance(blockedMoney);
                    awiDto.setWalletId(walletInfoDto.getWalletId());
                    awiDto.setType(walletInfoDto.getType());
                    awiDto.setCreateTime(walletInfoDto.getCreateTime());
                    awiDto.setVersion(walletInfoDto.getVersion());
                    ok = DozerUtils.map(accountApi.updateBlockedWallet(awiDto).getResult(),Boolean.class);
                    //冻结金额扣除成功，添加交易日志
                    if(ok){
                        bpd.setId(payInfoDO.getId());
                        //（余额支付）交易日志
                        payTradeFacade.payWalletBillInfo(oeiDto,bpd.getUserId());
                    }
                }
            }
        }else{
            ok = true;
        }
        //（在线支付）交易日志
        payTradeFacade.payBillInfo(bpd);
        return ok;
    }

    /**
     * 交易日志数据（在线支付）
     *
     * @param bpd
     * @param bpd
     */
    public void payBillInfo(BasePayDTO bpd) {
        Map<String, Object> saveData = PayBillDto.pay(bpd);
        Ensure.that(CommonsUtil.isEmptyMap(saveData)).isFalse("09000026"); //实体封装异常
        PayBillDto payBillDto = (PayBillDto) saveData.get("payBillDto");
        //是否需要获取用户的身份（商户还是用户）


        payBillDto.setOrderId(bpd.getId().toString());
        payBillDto.setType(bpd.getType());
        boolean flag = payBillService.createPayBill(payBillDto);    //支付账单表
        Ensure.that(flag).isTrue("09000029");
    }

    /**
     * 交易日志数据（余额支付）
     *
     * @param orderExpenseItemDto
     */
    public void payWalletBillInfo(OrderExpenseItemDto orderExpenseItemDto,Long memberId) {
        PayBillDto payBillDto = new PayBillDto();
        payBillDto.setOrderId(orderExpenseItemDto.getOrderId());
        payBillDto.setType(18);
        payBillDto.setAmount(orderExpenseItemDto.getAmount());
        payBillDto.setDemo("支付方式：余额支付");
        payBillDto.setRole(1);
        payBillDto.setMemberId(memberId);
        boolean flag = payBillService.createPayBill(payBillDto);//支付账单表
        Ensure.that(flag).isTrue("09000029");
    }

    public void deductBlockCoupon(BasePayDTO bpd){
        OrderCouponLogRequest orderCouponLogRequest = new OrderCouponLogRequest();
        orderCouponLogRequest.setMemberId(bpd.getUserId());
        orderCouponLogRequest.setOrderId(bpd.getOut_trade_no());
        orderCouponLogRequest.setType(CommonConstants.OrderCouponLogType.LOCK.getCode());
        List<OrderCouponLogResponse> orderCouponLogResponseList = DozerUtils.maps((List)orderApi.selectList(orderCouponLogRequest).getResult(),OrderCouponLogResponse.class);
        if (orderCouponLogResponseList != null && orderCouponLogResponseList.size() > 0){
            String couponIds = "";
            for (OrderCouponLogResponse oclResponse:orderCouponLogResponseList) {
                if(oclResponse != null && oclResponse.getCouponId() != null){
                    BaseCouponRequest baseCouponRequest = new BaseCouponRequest();
                    baseCouponRequest.setId(oclResponse.getCouponId());
                    baseCouponRequest.setLocked(false);
                    baseCouponRequest.setStatus(3);
                    baseApi.updateByKey(baseCouponRequest);
                    couponIds = couponIds + oclResponse.getCouponId() + ",";
                }
            }
            //批量修改订单中券流向记录
            OrderCouponLogRequest oclRequest = new OrderCouponLogRequest();
            oclRequest.setMemberId(bpd.getUserId());
            oclRequest.setOrderId(bpd.getOut_trade_no());
            orderApi.updateManyLog(oclRequest,couponIds);
        }
    }

    /**
     * 龙币充值
     *
     * @return
     */
    public boolean LbRecharge(BasePayDTO bpd,PayInfoDto payInfoDO) {
        BaseOrderDto baseOrderDto = DozerUtils.map(orderApi.findOrderByOrderId(payInfoDO.getSerialNumber()),BaseOrderDto.class);
        if(baseOrderDto != null && !BigDecimalUtil.isZeroOrNull(payInfoDO.getAmount())){
            //根据shopId、memberId获取钱包id
            AccountWalletDto accountWalletDto = DozerUtils.map(accountApi.findByMemberIdAndPlatformId(baseOrderDto.getMemberId(),baseOrderDto.getShopId()).getResult(),AccountWalletDto.class);
            if(accountWalletDto != null){
                AccountWalletInfoDto walletInfoDto = DozerUtils.map(accountApi.selectAvailableAccount(accountWalletDto.getId()).getResult(),AccountWalletInfoDto.class);
                if(walletInfoDto != null){
                    //更新可用余额
                    BigDecimal balance = walletInfoDto.getBalance().add(payInfoDO.getAmount());
                    walletInfoDto.setBalance(balance);
                    Boolean ok = DozerUtils.map(accountApi.updateByPrimaryKey(walletInfoDto),Boolean.class);
                    return true;
                }
            }
        }
        return false;
    }

}
